<?php

namespace Kangcg\Application\Base;

class Event
{
    public $name; // 事件名称
    public $sender; // 发起事件的对象
    public $handled = false; //事件处理是否中断
    public $data; // 携带的数据
    public static $events = []; // 存储所有事件监听信息

    /**
     * 注册事件监听器
     *
     * @param object $that 监听的对象
     * @param string $event 事件名称
     * @param callable|array|string $handler 事件处理程序，可以是可调用对象、数组（类方法）或字符串（函数名）
     * @param mixed $data 监听时携带的数据
     * @param bool $append 是否追加处理程序
     */
    public static function on(object $that, string $event, callable|array|string $handler, bool $append = true)
    {
        $className = get_class($that);
        // 确保类名对应的事件数组存在
        if (!isset(self::$events[$className])) {
            self::$events[$className] = [];
        }

        // 不追加，清空该事件的所有处理程序
        if (!$append) {
            self::$events[$className][$event] = [];
        }

        // 追加新的事件处理程序和数据
        self::$events[$className][$event][] = $handler;
    }

    /**
     * 移除事件监听器
     *
     * @param object $that 监听的对象
     * @param string $event 事件名称
     */
    public static function off(object $that, string $event)
    {
        $className = get_class($that);
        if (isset(self::$events[$className][$event])) {
            unset(self::$events[$className][$event]);
        }
    }
    /**
     * 判断是否绑定事件
     * @param object $that
     * @param string $event
     * @return bool
     */
    public static function has(object $that, string $event) :bool
    {
        $className = get_class($that);
        return isset(self::$events[$className][$event]);
    }

    /**
     * 触发事件
     *
     * @param object $that 触发事件的对象
     * @param string $event 事件名称
     * @param mixed $data 事件携带的数据
     */
    public static function trigger(object $that, string $name, Event $event = null)
    {
        $className = get_class($that);
        if (isset(self::$events[$className][$name])) {
            if (empty($event)) {
                $event = new static();
                $event->name = $name;
                $event->sender = $that;
            }

            $event->handled = false;
            // 遍历所有事件处理程序
            foreach (self::$events[$className][$name] as $handler) {
                try {
                    self::callEventHandler($handler, $that, $event);
                } catch (\Exception $e) {
                    throw $e;
                }

                //停止后续处理程序的执行
                if ($event->handled) {
                    return;
                }
            }
        }
    }

    public static function create(object $that, string $name, $data = null): static
    {
        $event = new static();
        $event->name = $name;
        $event->sender = $that;
        $event->handled = false;
        $event->data = $data;
        return $event;
    }
    /**
     * 调用事件处理程序
     *
     * @param callable|array|string $handler 事件处理程序
     * @param object $that 监听的对象
     * @param Event $eventObject 事件对象
     */
    private static function callEventHandler($handler, object $that, Event $eventObject)
    {
        if (is_callable($handler)) {
            call_user_func($handler, $eventObject);
        } elseif (is_array($handler)) {
            call_user_func($handler, $eventObject);
        } elseif (is_string($handler) && method_exists($that, $handler)) {
            call_user_func([$that, $handler], $eventObject);
        } elseif (is_string($handler) && function_exists($handler)) {
            call_user_func($handler, $eventObject);
        }
    }
}